/**
 * 
 */
package cn.cityhouse.avm.stat;

import org.apache.commons.math3.distribution.TDistribution;
import org.apache.commons.math3.exception.OutOfRangeException;
import org.apache.commons.math3.exception.util.LocalizedFormats;
import org.apache.commons.math3.linear.MatrixUtils;
import org.apache.commons.math3.linear.RealMatrix;
import org.apache.commons.math3.linear.RealVector;
import org.apache.commons.math3.stat.correlation.PearsonsCorrelation;
import org.apache.commons.math3.stat.descriptive.DescriptiveStatistics;
import org.apache.commons.math3.stat.descriptive.StatisticalSummary;
import org.apache.commons.math3.stat.descriptive.rank.Percentile;

import cn.cityhouse.avm.utils.DataFrame;
import cn.cityhouse.avm.utils.Out;

/**
 * @author <a href="mailto:wangcl@lreis.ac.cn">ChenLiang Wang</a>
 *
 */
public class SummaryStats {


	/**
	 * Confidence Intervals for Model Parameters
	 * @param val   Model Parameters
	 * @param nrow   number row of data
	 * @param int_k   number of independent variables
	 * @param se_error  standard error of parameters
	 * @param d_CI  confidence level
	 * @return   Vector { t-value, p-value, lower confidence, upper confidence}
	 */
	public static RealVector getConfint(double val,int nrow ,int int_k,double se_error,double d_CI){
		double d_df_coef =0.0+nrow-int_k;
		TDistribution t = new TDistribution(d_df_coef);
		//		double d_CI = 0.95;
		double d_tstatisc_coef = val/ se_error;
		// two-tailed test
		double d_pv_coef = 2 * (1 - t.cumulativeProbability(Math.abs(d_tstatisc_coef)));
		//		System.out.printf("%15s", Out.round(((1.0 - d_CI) * 50), 2) + " %:\t");
		double lowerBeta = val- SummaryStats.getBetaConfidenceInterval(se_error, 1 - d_CI, nrow);
		//		System.out.printf("%15s", Out.round((100 - (1.0 - d_CI) * 50), 2) + " %:\t");
		double upperBeta= val + SummaryStats.getBetaConfidenceInterval(se_error, 1 - d_CI, nrow);
		return  MatrixUtils.createRealVector( new double[]{d_tstatisc_coef,d_pv_coef,lowerBeta,upperBeta});
	}

	public static double getBetaConfidenceInterval(double d_sd, double d_alpha, int n) throws OutOfRangeException {
		// OLSMultipleLinearRegression regression, double d_alpha, int n,
		// int coef_i
		if (n < 3) {
			return Double.NaN;
		}
		if (d_alpha >= 1 || d_alpha <= 0) {
			throw new OutOfRangeException(LocalizedFormats.SIGNIFICANCE_LEVEL, d_alpha, 0, 1);
		}
		TDistribution distribution = new TDistribution(n - 2);
		// return
		// regression.estimateRegressionParametersStandardErrors()[coef_i]
		// * distribution.inverseCumulativeProbability(1d - d_alpha / 2d);
		return d_sd * distribution.inverseCumulativeProbability(1d - d_alpha / 2d);
	}

	public static double getConfidenceIntervalWidth(StatisticalSummary statistics, double significance) {
		TDistribution tDist = new TDistribution(statistics.getN() - 1);
		double a = tDist.inverseCumulativeProbability(1.0 - significance / 2);
		return a * statistics.getStandardDeviation() / Math.sqrt(statistics.getN());
	}

	public static double[] getCor(DataFrame data_frame, String y_name) {
		PearsonsCorrelation pcor = new PearsonsCorrelation(data_frame.getData_matrix());
		RealMatrix pcor_mat = pcor.getCorrelationMatrix();
		System.out.printf("%15s", "Correlation");
		Out.printArr(data_frame.getStr_colnames());
		System.out.println();
		for (int i = 0; i < data_frame.getNcol(); i++) {
			if (data_frame.getStr_colnames()[i].trim().equals(y_name)) {
				System.out.printf("%15s", data_frame.getStr_colnames()[i]);
				Out.printArr(pcor_mat.getRow(i));
				System.out.println();
				return pcor_mat.getRow(i);
			}
		}
		return null;
	}

	public static double[] getCorPV(DataFrame data_frame, String y_name) {
		PearsonsCorrelation pcor = new PearsonsCorrelation(data_frame.getData_matrix());
		RealMatrix pcor_pv = pcor.getCorrelationPValues();
		System.out.printf("%15s", "p value");
		Out.printArr(data_frame.getStr_colnames());
		System.out.println();
		for (int i = 0; i < data_frame.getNcol(); i++) {
			if (data_frame.getStr_colnames()[i].trim().equals(y_name)) {
				System.out.printf("%15s", data_frame.getStr_colnames()[i]);
				Out.printArr(pcor_pv.getRow(i), "%15.6e");
				System.out.println();
				return pcor_pv.getRow(i);
			}
		}
		return null;
	}

	public static DescriptiveStatistics summaryStats(double[] d_value) {
		DescriptiveStatistics u = new DescriptiveStatistics();
		for (int i = 0; i < d_value.length; i++) {
			u.addValue(d_value[i]);
		}
		// quantile Type 7 (R ,Excel )
		// m = 1-p. p[k] = (k - 1) / (n - 1). In this case, p[k] =
		// mode[F(x[k])]. This is used by S.
		u.setPercentileImpl(new Percentile().withEstimationType(Percentile.EstimationType.R_7));
		String[] summary_name = new String[] { "Min.", "1st Qu.", "Median", "Mean", "3rd Qu.", "Max.", "Std.", "Var." };
		Out.printArr(summary_name);
		System.out.println();
		double d_min = u.getMin();
		double d_mean = u.getMean();
		double d_max = u.getMax();
		double d_std = u.getStandardDeviation();
		double d_var = u.getVariance();
		double d_median = u.getPercentile(50);
		double d_quant25 = u.getPercentile(25);
		double d_quant75 = u.getPercentile(75);
		double[] summary_value = new double[] { d_min, d_quant25, d_median, d_mean, d_quant75, d_max, d_std, d_var };
		Out.printArr(summary_value);
		System.out.println();
		return u;
	}

	public static DescriptiveStatistics summaryStats(double[] d_value, boolean isPrint) {
		DescriptiveStatistics u = new DescriptiveStatistics();
		for (int i = 0; i < d_value.length; i++) {
			u.addValue(d_value[i]);
		}
		if (isPrint) {
			String[] summary_name = new String[] { "Min.", "1st Qu.", "Median", "Mean", "3rd Qu.", "Max.", "Std.",
			"Var." };
			Out.printArr(summary_name);
			double d_min = u.getMin();
			double d_mean = u.getMean();
			double d_max = u.getMax();
			double d_std = u.getStandardDeviation();
			double d_var = u.getVariance();
			double d_median = u.getPercentile(50);
			double d_quant25 = u.getPercentile(25);
			double d_quant75 = u.getPercentile(75);
			double[] summary_value = new double[] { d_min, d_quant25, d_median, d_mean, d_quant75, d_max, d_std,
					d_var };
			Out.printArr(summary_value);
		}
		return u;
	}

	/**
	 * 
	 */
	public SummaryStats() {
		// TODO Auto-generated constructor stub
	}

}
